{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# [模型组网](https://www.paddlepaddle.org.cn/documentation/docs/zh/guides/beginner/model_cn.html)\n",
    "\n",
    "* 直接使用内置模型\n",
    "\n",
    "* 使用 paddle.nn.Sequential 组网\n",
    "\n",
    "* 使用 paddle.nn.Layer 组网\n",
    "\n",
    "另外飞桨框架提供了 paddle.summary 函数方便查看网络结构、每层的输入输出 shape 和参数信息。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/usr/lib/python3/dist-packages/urllib3/util/selectors.py:14: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated since Python 3.3, and in 3.10 it will stop working\n",
      "  from collections import namedtuple, Mapping\n",
      "/usr/lib/python3/dist-packages/urllib3/_collections.py:2: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated since Python 3.3, and in 3.10 it will stop working\n",
      "  from collections import Mapping, MutableMapping\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "飞桨框架内置模型： ['ResNet', 'resnet18', 'resnet34', 'resnet50', 'resnet101', 'resnet152', 'VGG', 'vgg11', 'vgg13', 'vgg16', 'vgg19', 'MobileNetV1', 'mobilenet_v1', 'MobileNetV2', 'mobilenet_v2', 'LeNet']\n"
     ]
    }
   ],
   "source": [
    "import paddle\n",
    "\n",
    "print(\"飞桨框架内置模型：\", paddle.vision.models.__all__)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/usr/local/lib/python3.8/dist-packages/ipykernel/ipkernel.py:283: DeprecationWarning: `should_run_async` will not call `transform_cell` automatically in the future. Please pass the result to `transformed_cell` argument and any exception that happen during thetransform in `preprocessing_exc_tuple` in IPython 7.17 and above.\n",
      "  and should_run_async(code)\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "---------------------------------------------------------------------------\n",
      " Layer (type)       Input Shape          Output Shape         Param #    \n",
      "===========================================================================\n",
      "   Conv2D-1       [[1, 1, 28, 28]]      [1, 6, 28, 28]          60       \n",
      "    ReLU-1        [[1, 6, 28, 28]]      [1, 6, 28, 28]           0       \n",
      "  MaxPool2D-1     [[1, 6, 28, 28]]      [1, 6, 14, 14]           0       \n",
      "   Conv2D-2       [[1, 6, 14, 14]]     [1, 16, 10, 10]         2,416     \n",
      "    ReLU-2       [[1, 16, 10, 10]]     [1, 16, 10, 10]           0       \n",
      "  MaxPool2D-2    [[1, 16, 10, 10]]      [1, 16, 5, 5]            0       \n",
      "   Linear-1          [[1, 400]]            [1, 120]           48,120     \n",
      "   Linear-2          [[1, 120]]            [1, 84]            10,164     \n",
      "   Linear-3          [[1, 84]]             [1, 10]              850      \n",
      "===========================================================================\n",
      "Total params: 61,610\n",
      "Trainable params: 61,610\n",
      "Non-trainable params: 0\n",
      "---------------------------------------------------------------------------\n",
      "Input size (MB): 0.00\n",
      "Forward/backward pass size (MB): 0.11\n",
      "Params size (MB): 0.24\n",
      "Estimated Total Size (MB): 0.35\n",
      "---------------------------------------------------------------------------\n",
      "\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{'total_params': 61610, 'trainable_params': 61610}"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 模型组网并初始化网络\n",
    "lenet = paddle.vision.models.LeNet(num_classes=10)\n",
    "\n",
    "# 可视化模型组网结构和参数\n",
    "paddle.summary(lenet, (1, 1, 28, 28))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![](https://www.paddlepaddle.org.cn/documentation/docs/zh/_images/lenet.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "---------------------------------------------------------------------------\n",
      " Layer (type)       Input Shape          Output Shape         Param #    \n",
      "===========================================================================\n",
      "   Conv2D-5       [[1, 1, 28, 28]]      [1, 6, 28, 28]          60       \n",
      "    ReLU-5        [[1, 6, 28, 28]]      [1, 6, 28, 28]           0       \n",
      "  MaxPool2D-5     [[1, 6, 28, 28]]      [1, 6, 14, 14]           0       \n",
      "   Conv2D-6       [[1, 6, 14, 14]]     [1, 16, 10, 10]         2,416     \n",
      "    ReLU-6       [[1, 16, 10, 10]]     [1, 16, 10, 10]           0       \n",
      "  MaxPool2D-6    [[1, 16, 10, 10]]      [1, 16, 5, 5]            0       \n",
      "   Flatten-4      [[1, 16, 5, 5]]          [1, 400]              0       \n",
      "   Linear-7          [[1, 400]]            [1, 120]           48,120     \n",
      "   Linear-8          [[1, 120]]            [1, 84]            10,164     \n",
      "   Linear-9          [[1, 84]]             [1, 10]              850      \n",
      "===========================================================================\n",
      "Total params: 61,610\n",
      "Trainable params: 61,610\n",
      "Non-trainable params: 0\n",
      "---------------------------------------------------------------------------\n",
      "Input size (MB): 0.00\n",
      "Forward/backward pass size (MB): 0.11\n",
      "Params size (MB): 0.24\n",
      "Estimated Total Size (MB): 0.35\n",
      "---------------------------------------------------------------------------\n",
      "\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{'total_params': 61610, 'trainable_params': 61610}"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from paddle import nn\n",
    "\n",
    "lenet_Sequential = nn.Sequential(\n",
    "    nn.Conv2D(1, 6, 3, stride=1, padding=1),\n",
    "    nn.ReLU(),\n",
    "    nn.MaxPool2D(2),\n",
    "    nn.Conv2D(6, 16, 5, stride=1, padding=0),\n",
    "    nn.ReLU(),\n",
    "    nn.MaxPool2D(2),\n",
    "    nn.Flatten(),\n",
    "    nn.Linear(400, 120),\n",
    "    nn.Linear(120, 84),\n",
    "    nn.Linear(84, 10)\n",
    ")\n",
    "# 可视化模型组网结构和参数\n",
    "paddle.summary(lenet_Sequential, (1, 1, 28, 28))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Sequential(\n",
      "  (0): Conv2D(1, 6, kernel_size=[3, 3], padding=1, data_format=NCHW)\n",
      "  (1): ReLU()\n",
      "  (2): MaxPool2D(kernel_size=2, stride=None, padding=0)\n",
      "  (3): Conv2D(6, 16, kernel_size=[5, 5], data_format=NCHW)\n",
      "  (4): ReLU()\n",
      "  (5): MaxPool2D(kernel_size=2, stride=None, padding=0)\n",
      "  (6): Flatten()\n",
      "  (7): Linear(in_features=400, out_features=120, dtype=float32)\n",
      "  (8): Linear(in_features=120, out_features=84, dtype=float32)\n",
      "  (9): Linear(in_features=84, out_features=10, dtype=float32)\n",
      ")\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/usr/local/lib/python3.8/dist-packages/ipykernel/ipkernel.py:283: DeprecationWarning: `should_run_async` will not call `transform_cell` automatically in the future. Please pass the result to `transformed_cell` argument and any exception that happen during thetransform in `preprocessing_exc_tuple` in IPython 7.17 and above.\n",
      "  and should_run_async(code)\n"
     ]
    }
   ],
   "source": [
    "print(lenet_Sequential)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "LeNet(\n",
      "  (features): Sequential(\n",
      "    (0): Conv2D(1, 6, kernel_size=[3, 3], padding=1, data_format=NCHW)\n",
      "    (1): ReLU()\n",
      "    (2): MaxPool2D(kernel_size=2, stride=2, padding=0)\n",
      "    (3): Conv2D(6, 16, kernel_size=[5, 5], data_format=NCHW)\n",
      "    (4): ReLU()\n",
      "    (5): MaxPool2D(kernel_size=2, stride=2, padding=0)\n",
      "  )\n",
      "  (fc): Sequential(\n",
      "    (0): Linear(in_features=400, out_features=120, dtype=float32)\n",
      "    (1): Linear(in_features=120, out_features=84, dtype=float32)\n",
      "    (2): Linear(in_features=84, out_features=10, dtype=float32)\n",
      "  )\n",
      ")\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/usr/local/lib/python3.8/dist-packages/ipykernel/ipkernel.py:283: DeprecationWarning: `should_run_async` will not call `transform_cell` automatically in the future. Please pass the result to `transformed_cell` argument and any exception that happen during thetransform in `preprocessing_exc_tuple` in IPython 7.17 and above.\n",
      "  and should_run_async(code)\n"
     ]
    }
   ],
   "source": [
    "print(lenet)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 使用 paddle.nn.Layer 组网\n",
    "构建一些比较复杂的网络结构时，可以选择该方式，组网包括三个步骤：\n",
    "\n",
    "1. 创建一个继承自 paddle.nn.Layer 的类；\n",
    "\n",
    "2. 在类的构造函数 __init__ 中定义组网用到的神经网络层（layer）；\n",
    "\n",
    "3. 在类的前向计算函数 forward 中使用定义好的 layer 执行前向计算。\n",
    "\n",
    "仍然以 LeNet 模型为例，使用 paddle.nn.Layer 组网的代码如下："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "---------------------------------------------------------------------------\n",
      " Layer (type)       Input Shape          Output Shape         Param #    \n",
      "===========================================================================\n",
      "   Conv2D-7       [[1, 1, 28, 28]]      [1, 6, 28, 28]          60       \n",
      "    ReLU-7        [[1, 6, 28, 28]]      [1, 6, 28, 28]           0       \n",
      "  MaxPool2D-7     [[1, 6, 28, 28]]      [1, 6, 14, 14]           0       \n",
      "   Conv2D-8       [[1, 6, 14, 14]]     [1, 16, 10, 10]         2,416     \n",
      "    ReLU-8       [[1, 16, 10, 10]]     [1, 16, 10, 10]           0       \n",
      "  MaxPool2D-8    [[1, 16, 10, 10]]      [1, 16, 5, 5]            0       \n",
      "   Linear-10         [[1, 400]]            [1, 120]           48,120     \n",
      "   Linear-11         [[1, 120]]            [1, 84]            10,164     \n",
      "   Linear-12         [[1, 84]]             [1, 10]              850      \n",
      "===========================================================================\n",
      "Total params: 61,610\n",
      "Trainable params: 61,610\n",
      "Non-trainable params: 0\n",
      "---------------------------------------------------------------------------\n",
      "Input size (MB): 0.00\n",
      "Forward/backward pass size (MB): 0.11\n",
      "Params size (MB): 0.24\n",
      "Estimated Total Size (MB): 0.35\n",
      "---------------------------------------------------------------------------\n",
      "\n",
      "{'total_params': 61610, 'trainable_params': 61610}\n"
     ]
    },
    {
     "ename": "",
     "evalue": "",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m在当前单元格或上一个单元格中执行代码时 Kernel 崩溃。\n",
      "\u001b[1;31m请查看单元格中的代码，以确定故障的可能原因。\n",
      "\u001b[1;31m单击<a href='https://aka.ms/vscodeJupyterKernelCrash'>此处</a>了解详细信息。\n",
      "\u001b[1;31m有关更多详细信息，请查看 Jupyter <a href='command:jupyter.viewOutput'>log</a>。"
     ]
    }
   ],
   "source": [
    "class LeNetCustom(paddle.nn.Layer):\n",
    "    def __init__(self, num_classes=10):\n",
    "        super().__init__()\n",
    "        self.num_classes = num_classes\n",
    "        # 构建 features 子网，用于对输入图像进行特征提取\n",
    "        self.features = nn.Sequential(\n",
    "            nn.Conv2D(1, 6, 3, stride=1, padding=1),\n",
    "            nn.ReLU(),\n",
    "            nn.MaxPool2D(2, 2),\n",
    "            nn.Conv2D(6, 16, 5, stride=1, padding=0),\n",
    "            nn.ReLU(),\n",
    "            nn.MaxPool2D(2, 2),\n",
    "        )\n",
    "        # 构建 linear 子网，用于分类\n",
    "        if num_classes > 0:\n",
    "            self.linear = nn.Sequential(\n",
    "                nn.Linear(400, 120),\n",
    "                nn.Linear(120, 84),\n",
    "                nn.Linear(84, num_classes),\n",
    "            )\n",
    "    # 执行前向计算\n",
    "    def forward(self, inputs):\n",
    "        x = self.features(inputs)\n",
    "\n",
    "        if self.num_classes > 0:\n",
    "            x = paddle.flatten(x, 1)\n",
    "            x = self.linear(x)\n",
    "        return x\n",
    "lenet_SubClass = LeNetCustom()\n",
    "\n",
    "# 可视化模型组网结构和参数\n",
    "params_info = paddle.summary(lenet_SubClass, (1, 1, 28, 28))\n",
    "print(params_info)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![](https://www.paddlepaddle.org.cn/documentation/docs/zh/_images/model.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
